package util;

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.JwtBuilder;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.io.Decoders;
import io.jsonwebtoken.io.Encoders;
import io.jsonwebtoken.security.Keys;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;

import javax.crypto.SecretKey;
import java.util.Calendar;
import java.util.Date;
import java.util.Optional;
import java.util.concurrent.TimeUnit;

public class JwtUtil {

    @Autowired
    private RedisTemplate redisTemplate;

    private static Long ttl;

    static {
        ttl = 1000 * 60 * 60 * 24L;//一天
    }

    /**
     * 生成JWT
     *
     * @param id
     * @param subject
     * @param roles
     * @return
     */
    public String createJWS(String id, String subject, String roles) {
        SecretKey secretKey = null;
        String secretKeyString = (String) redisTemplate.opsForValue().get("secretKey");

        if (secretKeyString == null) {
            secretKey = Keys.secretKeyFor(SignatureAlgorithm.HS256);
            String encode = parseSecretKeyToBase64(secretKey);
            redisTemplate.opsForValue().set("secretKey", encode, 1, TimeUnit.DAYS);
        } else {
            secretKey = parseBase64ToSecretKey(secretKeyString);
        }

        Long timeMillis = System.currentTimeMillis();
        Calendar calendar = Calendar.getInstance();
        calendar.setTimeInMillis(timeMillis);
        Date now = calendar.getTime();

        JwtBuilder builder = Jwts.builder()
                .setId(id)
                .setSubject(subject)
                .setIssuedAt(now)
                .signWith(secretKey)
                .claim("roles", roles);
        Optional.ofNullable(ttl)
                .filter(t -> t > 0)
                .ifPresent(t -> {
                    calendar.setTimeInMillis(timeMillis + t);
                    Date afterTtlTime = calendar.getTime();
                    builder.setExpiration(afterTtlTime);
                });
        return builder.compact();
    }

    /**
     * 解析JWT
     *
     * @param jws
     * @return
     */
    public Claims parseJWT(String jws) {
        String secretKey = String.valueOf(redisTemplate.opsForValue().get("secretKey"));
        return Jwts.parserBuilder()
                .setSigningKey(secretKey)
                .build()
                .parseClaimsJws(jws)
                .getBody();
    }

    public String parseSecretKeyToBase64(SecretKey secretKey) {
        return Encoders.BASE64.encode(secretKey.getEncoded());
    }

    public SecretKey parseBase64ToSecretKey(String encode) {
        return Keys.hmacShaKeyFor(Decoders.BASE64.decode(encode));
    }

}
